﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media;
namespace MsPictureTool
{
	[TemplatePart(Name = "PART_Image", Type = typeof(Image))]
	[TemplatePart(Name = "PART_StackPanel", Type = typeof(StackPanel))]
	public class MsImage : ContentControl
	{
		static MsImage()
		{
			DefaultStyleKeyProperty.OverrideMetadata(typeof(MsImage), new FrameworkPropertyMetadata(typeof(MsImage)));
		}
		Image image;
		StackPanel stackPanel;
		/// <summary>
		/// 当前控件所在的window窗口
		/// </summary>
		Window owner;
		/// <summary>
		/// 控件双击后打开的窗口
		/// </summary>
		Window window;
		ImageSource _ImageSource = new BitmapImage(new Uri("pack://application:,,,/MsPictureTool;component/NoPicture.png"));
		/// <summary>
		/// 最大缩放倍数
		/// </summary>
		const double MaxMultiple = 10;
		/// <summary>
		/// 缩放倍数
		/// </summary>
		double Multiple;
		/// <summary>
		/// 滚轮触发时鼠标所在点占宽度的比例
		/// </summary>
		double Xproportion;
		/// <summary>
		/// 滚轮触发时鼠标所在点占高度的比例
		/// </summary>
		double Yproportion;
		/// <summary>
		/// image控件实际宽度
		/// </summary>
		double RealWidth;
		/// <summary>
		/// image控件实际高度
		/// </summary>
		double RealHeight;

		/// <summary>
		/// image控件原始宽度
		/// </summary>
		double OriginalWidth;
		/// <summary>
		/// image控件原始高度
		/// </summary>
		double OriginalHeight;
		/// <summary>
		/// 缩放堆栈
		/// </summary>
		Stack<ActionModel> stack = new Stack<ActionModel>();
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			image = this.GetTemplateChild("PART_Image") as Image;
			stackPanel = this.GetTemplateChild("PART_StackPanel") as StackPanel;
			image.PreviewMouseWheel += image_PreviewMouseWheel;
			this.Loaded += MsImage_Loaded;
		}

		void MsImage_Loaded(object sender, RoutedEventArgs e)
		{
			image.Source = _ImageSource;
			image.Width = stackPanel.ActualWidth;
			image.Height = stackPanel.ActualHeight;
			owner = GetParentObject<Window>(this);
			if (owner!=null)
			{
				var s = owner.GetHashCode();
				if (!(owner.Tag != null && owner.Tag.ToString() == ("图片查看器窗口" + s)))
				{
					image.PreviewMouseLeftButtonDown += image_PreviewMouseLeftButtonDown;
				}
			}
		}

		void image_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			if (LastClickTime == null)
			{
				LastClickTime = DateTime.Now;
			}
			else
			{
				var now = DateTime.Now;
				var span = now - LastClickTime;
				LastClickTime = now;
				if (span < TimeSpan.FromSeconds(0.5))
				{
					if (owner != null)
					{
						owner.Activate();
						window = new Window()
						{
							Content = new MsImage() { ImageSource = this.ImageSource.Clone() },
							ShowInTaskbar = false,
							WindowStyle = WindowStyle.None,
							ShowActivated=true,
							Owner = owner,
						};
						window.Tag = "图片查看器窗口" + window.GetHashCode();
						window.MouseDoubleClick += window_MouseDoubleClick;
						window.Top = 0;
						window.Left = 0;
						window.Width = SystemParameters.PrimaryScreenWidth;
						window.Height = SystemParameters.PrimaryScreenHeight;
						window.Show();
					}
				}

			}
		}

		void window_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			Window win = sender as Window;
			win.Close();
			owner.Activate();
		}
		/// <summary>
		/// 找到第一个符合条件的控件
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <param name="name"></param>
		/// <returns></returns>
		public static T GetParentObject<T>(DependencyObject obj) where T : FrameworkElement
		{
			DependencyObject parent = VisualTreeHelper.GetParent(obj);
			while (parent != null)
			{
				if (parent is T)
				{
					return (T)parent;
				}
				parent = VisualTreeHelper.GetParent(parent);
			}
			return null;
		}

		DateTime? LastClickTime;


		void image_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
		{
			if (image.IsMouseOver)
			{
				if (OriginalHeight == 0 && OriginalWidth == 0)
				{
					RealHeight = OriginalHeight = image.ActualHeight;
					RealWidth = OriginalWidth = image.ActualWidth;
				}
				double left;
				double top;
				Point point = e.GetPosition(this.image);
				Xproportion = point.X / RealWidth;
				Yproportion = point.Y / RealHeight;
				ActionModel ActionModel;
				if (e.Delta > 0)
				{
					if (Multiple > MaxMultiple)
						return;
					RealHeight += OriginalHeight;
					RealWidth += OriginalWidth;
					left = RealWidth * Xproportion - point.X;
					top = RealHeight * Yproportion - point.Y;
					ActionModel = new ActionModel()
					{
						Height = RealHeight,
						Width = RealWidth,
						Left = left,
						Top = top
					};
					stack.Push(ActionModel);
					Zoom(ActionModel, 1);
				}
				else
				{
					if (stack.Count > 0)
					{
						ActionModel = stack.Pop();
						Zoom(ActionModel, -1);
					}
				}

			}
		}
		void Zoom(ActionModel ActionModel, int Symbol)
		{
			Multiple += Symbol;
			RealHeight = Symbol == 1 ? ActionModel.Height : ActionModel.Height - OriginalHeight;
			RealWidth = Symbol == 1 ? ActionModel.Width : ActionModel.Width - OriginalWidth;
			image.Width = Symbol == 1 ? ActionModel.Width : ActionModel.Width - OriginalWidth;
			image.Height = Symbol == 1 ? ActionModel.Height : ActionModel.Height - OriginalHeight;
			image.Margin = new Thickness()
			{
				Left = image.Margin.Left - Symbol * ActionModel.Left,
				Top = image.Margin.Top - Symbol * ActionModel.Top
			};
		}


		public ImageSource ImageSource
		{
			get { return (ImageSource)GetValue(ImageSourceProperty); }
			set { SetValue(ImageSourceProperty, value); }
		}

		// Using a DependencyProperty as the backing store for ImageSource.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty ImageSourceProperty =
			DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(MsImage), new PropertyMetadata(null, SourceChanged));

		private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			MsImage MsImage = d as MsImage;
			if (MsImage.image != null)
			{
				MsImage.image.Source = e.NewValue as ImageSource;
			}
			MsImage._ImageSource = e.NewValue as ImageSource;
		}
	}
}
